]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
st-theme-node: Improve borders with gradient backgrounds
authorFlorian Müllner <fmuellner@gnome.org>
Thu, 9 Dec 2010 09:35:40 +0000 (10:35 +0100)
committerFlorian Müllner <fmuellner@gnome.org>
Mon, 13 Dec 2010 17:15:00 +0000 (18:15 +0100)
For gradient backgrounds, borders were implemented by filling the
background shape with the border color first, and then scaling down
the path to draw the background.

The result is not correct[0], which is especially visible if the border
width is greater than the border radius - so instead of scaling down
the original path, use a separate path for the background.

The result is consistent with the borders we draw for non-gradient
backgrounds, and much closer to the correct standard behavior.

[0] http://www.w3.org/TR/css3-background/#the-border-radius

https://bugzilla.gnome.org/show_bug.cgi?id=607500

src/st/st-theme-node-drawing.c

index 847c7bb752989fd607762cc537c155a82f5d5392..4a17ac2da548994d200e77d828926fdffb634b8f 100644 (file)
@@ -378,7 +378,6 @@ st_theme_node_render_gradient (StThemeNode *node)
   cairo_t *cr;
   cairo_surface_t *surface;
   cairo_pattern_t *pattern;
-  gboolean round_border = FALSE;
   ClutterColor border_color;
   int border_width;
   guint rowstride;
@@ -397,11 +396,7 @@ st_theme_node_render_gradient (StThemeNode *node)
   get_arbitrary_border (node, &border_width, &border_color);
 
   for (i = 0; i < 4; i++)
-    {
-      radius[i] = st_theme_node_get_border_radius (node, i);
-      if (radius[i] > 0)
-        round_border = TRUE;
-    }
+    radius[i] = st_theme_node_get_border_radius (node, i);
 
   if (node->background_gradient_type == ST_GRADIENT_VERTICAL)
     pattern = cairo_pattern_create_linear (0, 0, 0, node->alloc_height);
@@ -427,57 +422,92 @@ st_theme_node_render_gradient (StThemeNode *node)
                                      node->background_gradient_end.blue / 255.,
                                      node->background_gradient_end.alpha / 255.);
 
-  if (round_border)
+  /* Create a path for the background's outline first */
+  if (radius[ST_CORNER_TOPLEFT] > 0)
+    cairo_arc (cr,
+               radius[ST_CORNER_TOPLEFT],
+               radius[ST_CORNER_TOPLEFT],
+               radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
+  else
+    cairo_move_to (cr, 0, 0);
+  cairo_line_to (cr, node->alloc_width - radius[ST_CORNER_TOPRIGHT], 0);
+  if (radius[ST_CORNER_TOPRIGHT] > 0)
+    cairo_arc (cr,
+               node->alloc_width - radius[ST_CORNER_TOPRIGHT],
+               radius[ST_CORNER_TOPRIGHT],
+               radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
+  cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
+  if (radius[ST_CORNER_BOTTOMRIGHT])
+    cairo_arc (cr,
+               node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
+               node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
+               radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
+  cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
+  if (radius[ST_CORNER_BOTTOMLEFT])
+    cairo_arc (cr,
+               radius[ST_CORNER_BOTTOMLEFT],
+               node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
+               radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
+  cairo_close_path (cr);
+
+
+  /* If we have a border, we fill the outline with the border
+   * color and create the inline shape for the background gradient;
+   * otherwise the outline shape is filled with the background
+   * gradient directly
+   */
+  if (border_width > 0)
     {
-      if (radius[ST_CORNER_TOPLEFT] > 0)
+      cairo_set_source_rgba (cr,
+                             border_color.red / 255.,
+                             border_color.green / 255.,
+                             border_color.blue / 255.,
+                             border_color.alpha / 255.);
+      cairo_fill (cr);
+
+      if (radius[ST_CORNER_TOPLEFT] > border_width)
         cairo_arc (cr,
                    radius[ST_CORNER_TOPLEFT],
                    radius[ST_CORNER_TOPLEFT],
-                   radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
+                   radius[ST_CORNER_TOPLEFT] - border_width,
+                   M_PI, 3 * M_PI / 2);
       else
-        cairo_move_to (cr, 0, 0);
-      cairo_line_to (cr, node->alloc_width - radius[ST_CORNER_TOPRIGHT], 0);
-      if (radius[ST_CORNER_TOPRIGHT] > 0)
+        cairo_move_to (cr, border_width, border_width);
+
+      cairo_line_to (cr,
+                     node->alloc_width - MAX(radius[ST_CORNER_TOPRIGHT], border_width),
+                     border_width);
+
+      if (radius[ST_CORNER_TOPRIGHT] > border_width)
         cairo_arc (cr,
                    node->alloc_width - radius[ST_CORNER_TOPRIGHT],
                    radius[ST_CORNER_TOPRIGHT],
-                   radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
-      cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
-      if (radius[ST_CORNER_BOTTOMRIGHT])
+                   radius[ST_CORNER_TOPRIGHT] - border_width,
+                   3 * M_PI / 2, 2 * M_PI);
+
+      cairo_line_to (cr,
+                     node->alloc_width - border_width,
+                     node->alloc_height - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width));
+
+      if (radius[ST_CORNER_BOTTOMRIGHT] > border_width)
         cairo_arc (cr,
                    node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
                    node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
-                   radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
-      cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
-      if (radius[ST_CORNER_BOTTOMLEFT])
+                   radius[ST_CORNER_BOTTOMRIGHT] - border_width,
+                   0, M_PI / 2);
+
+      cairo_line_to (cr,
+                     MAX(radius[ST_CORNER_BOTTOMLEFT], border_width),
+                     node->alloc_height - border_width);
+
+      if (radius[ST_CORNER_BOTTOMLEFT] > border_width)
         cairo_arc (cr,
                    radius[ST_CORNER_BOTTOMLEFT],
                    node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
-                   radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
+                   radius[ST_CORNER_BOTTOMLEFT] - border_width,
+                   M_PI / 2, M_PI);
       cairo_close_path (cr);
     }
-  else
-    cairo_rectangle (cr, 0, 0, node->alloc_width, node->alloc_height);
-
-  if (border_width > 0)
-    {
-      cairo_path_t *path;
-
-      path = cairo_copy_path (cr);
-      cairo_set_source_rgba (cr,
-                             border_color.red / 255.,
-                             border_color.green / 255.,
-                             border_color.blue / 255.,
-                             border_color.alpha / 255.);
-      cairo_fill (cr);
-
-      cairo_translate (cr, border_width, border_width);
-      cairo_scale (cr,
-                   (gdouble)(node->alloc_width - 2 * border_width) / node->alloc_width,
-                   (gdouble)(node->alloc_height - 2 * border_width) / node->alloc_height);
-      cairo_append_path (cr, path);
-      cairo_path_destroy (path);
-    }
 
   cairo_set_source (cr, pattern);
   cairo_fill (cr);